<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
   
  <meta name="keywords" content="Java Python" />
   
  <meta name="description" content="From Zero to Hero" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    JDK1.8源码-01-java.lang.Object |  朱酱酱的学习博客
  </title>
  <meta name="generator" content="hexo-theme-yilia-plus">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/css/style.css">

  
<script src="/js/pace.min.js"></script>


  

  

<link rel="alternate" href="/atom.xml" title="朱酱酱的学习博客" type="application/atom+xml">
</head>

</html>

<body>
  <div id="app">
    <main class="content">
      <section class="outer">
  <article id="post-jdk_SourceCode/JDK1.8-01-Object" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  JDK1.8源码-01-java.lang.Object
</h1>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/04/01/jdk_SourceCode/JDK1.8-01-Object/" class="article-date">
  <time datetime="2020-04-01T07:52:53.000Z" itemprop="datePublished">2020-04-01</time>
</a>
      
      
      
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">6.3k字</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">24分钟</span>
        </span>
    </span>
</div>

      
    </div>
    

    
    
    <div class="tocbot"></div>





    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="JDK1-8源码-01-java-lang-Object"><a href="#JDK1-8源码-01-java-lang-Object" class="headerlink" title="JDK1.8源码-01-java.lang.Object"></a>JDK1.8源码-01-java.lang.Object</h1><h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h2><p><strong>首先介绍JDK所有类的基类–java.lang.Object。</strong></p>
<ul>
<li><p>Object类属于java.lang包，此包下的所有类在使用的时候无需手动导入，系统会在程序编译期间自动导入。</p>
</li>
<li><p>Object 类是所有类的基类，当一个类没有直接继承某个类时，默认继承Object类，也就是说任何类都直接或间接继承此类</p>
</li>
<li><p>Object 类中能访问的方法在所有类中都可以调用</p>
</li>
</ul>
<p>下面我们会分别介绍Object 类中的所有方法。</p>
<a id="more"></a>



<h3 id="1-1-Object类图"><a href="#1-1-Object类图" class="headerlink" title="1.1 Object类图"></a>1.1 Object类图</h3><p><img src="http://zhuuu-bucket.oss-cn-beijing.aliyuncs.com/img/20200416/160846014.png" alt="mark"></p>
<h3 id="1-2-源码"><a href="#1-2-源码" class="headerlink" title="1.2 源码"></a>1.2 源码</h3><p>Object.class类(源码)</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.</span></span><br><span class="line"><span class="comment"> * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> java.lang;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Class &#123;<span class="doctag">@code</span> Object&#125; is the root of the class hierarchy.</span></span><br><span class="line"><span class="comment"> * Every class has &#123;<span class="doctag">@code</span> Object&#125; as a superclass. All objects,</span></span><br><span class="line"><span class="comment"> * including arrays, implement the methods of this class.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  unascribed</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     java.lang.Class</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span>   JDK1.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Object</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">registerNatives</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        registerNatives();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> Class&lt;?&gt; getClass();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">native</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="keyword">this</span> == obj);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">native</span> Object <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> getClass().getName() + <span class="string">"@"</span> + Integer.toHexString(hashCode());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">notify</span><span class="params">()</span></span>;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">notifyAll</span><span class="params">()</span></span>;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">wait</span><span class="params">(<span class="keyword">long</span> timeout)</span> <span class="keyword">throws</span> InterruptedException</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">wait</span><span class="params">(<span class="keyword">long</span> timeout, <span class="keyword">int</span> nanos)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (timeout &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"timeout value is negative"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (nanos &lt; <span class="number">0</span> || nanos &gt; <span class="number">999999</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(</span><br><span class="line">                    <span class="string">"nanosecond timeout value out of range"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (nanos &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            timeout++;</span><br><span class="line">        &#125;</span><br><span class="line">        wait(timeout);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">wait</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        wait(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable </span>&#123; &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="1-3-为什么java-lang包下的类不需要手动导入？"><a href="#1-3-为什么java-lang包下的类不需要手动导入？" class="headerlink" title="1.3 为什么java.lang包下的类不需要手动导入？"></a>1.3 为什么java.lang包下的类不需要手动导入？</h3><p>　不知道大家注意到没，我们在使用诸如Date类时，需要手动导入import java.util.Date，再比如使用File类时，也需要手动导入import java.io.File。</p>
<p><strong>但是我们在使用Object类，String类，Integer类等不需要手动导入，而是能直接使用</strong>，这是为什么呢？</p>
<p>这里先告诉大家一个结论：<strong>使用 java.lang 包下的所有类，都不需要手动导入。</strong></p>
<p>另外介绍一下Java中的两种导包形式，导包形式有两种方法：</p>
<p>①、单类型导入（single-type-import），例如import java.util.Date</p>
<p>②、按需类型导入(type-import-on-demand)，例如import java.util.*</p>
<p><strong>单类型</strong> ： 导入比较好理解，编程中所使用的各种工具默认都是按照单类型导包的，需要什么类型便导入什么类，这种方式是导入指定的public类或者接口。</p>
<p><strong>按需导入类型</strong> ： 比如import java.util.* ，可能看到后面的<em>,大家会误以为是导入java.util下面所有的类，*</em>其实不是的**，根据名字按需导入要知道他是按照需求导入，并不是导入整个包下的所有类。</p>
<p>Java编译器会从启动目录(bootstrap)，扩展目录(extension)和用户类路径下去定位需要导入的类，而这些目录进仅仅是给出了类的顶层目录，编译器的类文件定位方法大致可以理解为如下公式：　</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">顶层路径名 \ 包名 \ 文件名.class = 绝对路径</span><br></pre></td></tr></table></figure>

<p><strong>单类型导入</strong>我们知道包名和文件名，所以编译器可以一次性查找定位到所要的类文件。</p>
<p><strong>按需导入</strong>则比较复杂，编译器会把包名和文件名进行排列组合，然后对所有可能性进行类文件查找定位。例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br></pre></td></tr></table></figure>

<p>①、File 　　　　　　// File类属于无名包，就是说File类没有package语句，编译器会首先搜索无名包</p>
<p>②、com.File 　　　　// File类属于当前包，就是我们当前编译类的包路径</p>
<p>③、java.lang.File 　　//由于编译器会自动导入java.lang包，所以也会从该包下查找</p>
<p>④、java.io.File</p>
<p>⑤、java.util.File</p>
<p>需要注意的地方就是，编译器找到java.io.File类之后并不会停止下一步的寻找，<strong>而要把所有的可能性都查找完以确定是否有类导入冲突。假设此时的顶层路径有三个，那么编译器就会进行3*5=15次查找。</strong></p>
<p>如果在查找完成后，编译器发现了两个同名的类，那么就会报错。要删除你不用的那个类，然后再编译。</p>
<p>　所以我们可以得出这样的结论：<strong>按需类型导入是绝对不会降低Java代码的执行效率的，但会影响到Java代码的编译速度。</strong>所以我们在编码时最好是使用单类型导入，这样不仅能提高编译速度，也能避免命名冲突。</p>
<p>讲清楚Java的两种导包类型了，我们在回到为什么可以直接使用 Object 类，看到上面查找类文件的第③步，<strong>编译器会自动导入 java.lang 包</strong>，那么当然我们能直接使用了。至于原因，因为用的多，提前加载了，省资源。</p>
<h2 id="2-类构造器"><a href="#2-类构造器" class="headerlink" title="2. 类构造器"></a>2. 类构造器</h2><ul>
<li><p>类构造器是创建Java对象的途径之一，通过new关键字调用构造器完成对象的实例化，还能通过构造器对对象进行初始化。</p>
</li>
<li><p>一个类必须要有一个构造器的存在，如果没有显示声明，那么系统会默认创造一个无参构造器。</p>
</li>
<li><p><strong>在JDK的Object类源码中，是看不到构造器的，系统会自动添加一个无参构造器。我们可以通过：</strong></p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 构造一个Object类的对象</span></span><br><span class="line">Object obj = <span class="keyword">new</span> Object();。</span><br></pre></td></tr></table></figure>



<h2 id="3-equals-方法"><a href="#3-equals-方法" class="headerlink" title="3. equals() 方法"></a>3. equals() 方法</h2><p>通常很多面试题都会问 equals() 方法和 == 运算符的区别：</p>
<ul>
<li>== 运算符用于比较基本类型的值是否相同</li>
<li>或者比较两个对象的引用是否相等</li>
</ul>
<p><strong>而equals用于比较两个对象是否相等：</strong></p>
<p>这样说可能比较宽泛，两个对象如何才是相等的呢？这个标尺该如何定？</p>
<p>可以看看 Object 类中的equals 方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="keyword">this</span> == obj);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到，<strong>在 Object 类中，== 运算符和 equals 方法是等价的，都是比较两个对象的引用是否相等，</strong></p>
<p><strong>从另一方面来讲，如果两个对象的引用相等，那么这两个对象一定是相等的。</strong></p>
<p>对于我们自定义的一个对象，如果不重写 equals 方法，那么在比较对象的时候就是调用 Object 类的 equals 方法，也就是用 == 运算符比较两个对象。我们可以看看 String 类中的重写的 equals 方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object anObject)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span> == anObject) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (anObject <span class="keyword">instanceof</span> String) &#123;</span><br><span class="line">            String anotherString = (String)anObject;</span><br><span class="line">            <span class="keyword">int</span> n = value.length;</span><br><span class="line">            <span class="keyword">if</span> (n == anotherString.value.length) &#123;</span><br><span class="line">                <span class="keyword">char</span> v1[] = value;</span><br><span class="line">                <span class="keyword">char</span> v2[] = anotherString.value;</span><br><span class="line">                <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">                <span class="keyword">while</span> (n-- != <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (v1[i] != v2[i])</span><br><span class="line">                        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">                    i++;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>String是引用类型，比较时不能判断引用是否想到那个，重点是字符串的内容是否相等。所以String类型定义的两个对象相等的标准是<strong>字符串内容都相同</strong>。</p>
<p>在Java规范中，对 equals 方法的使用必须遵循以下几个原则：</p>
<ul>
<li>自反性：对于任何非空引用值x, x.equals(x)都应该返回true</li>
<li><strong>对称性</strong>：对于任何非空引用值x和y，当且仅当y.equals(x)返回true时，x.equals(y) 才应返回 true。 </li>
<li><strong>传递性</strong>：对于任何非空引用值 x、y 和 z，如果 x.equals(y) 返回 true，并且 y.equals(z) 返回 true，那么 x.equals(z) 应返回 true。</li>
<li><strong>一致性：</strong>对于任何非空引用值 x 和 y，多次调用 x.equals(y) 始终返回 true 或始终返回 false，前提是对象上 equals 比较中所用的信息没有被修改</li>
<li><strong>对于任何非空引用值x</strong>， x.equals（null）都应该返回false。</li>
</ul>
<p>下面我们自定义一个 Person 类，然后重写其equals 方法，比较两个 Person 对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.zhuuu;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(String name, <span class="keyword">int</span> age)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">        <span class="keyword">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 自己重写equals方法</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 两个对象引用相同，那么两个对象肯定相等</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span> == obj)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 如果对象为空或者不是Person的实例</span></span><br><span class="line">        <span class="keyword">if</span> (obj == <span class="keyword">null</span> || !(obj <span class="keyword">instanceof</span> Person))&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Person otherPerson = (Person) obj;</span><br><span class="line">        <span class="keyword">if</span> (otherPerson.getName().equals(<span class="keyword">this</span>.getName()) &amp;&amp; otherPerson.getAge()==<span class="keyword">this</span>.getAge())&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Person p1 = <span class="keyword">new</span> Person(<span class="string">"朱酱酱"</span>, <span class="number">24</span>);</span><br><span class="line">        Person p2 = <span class="keyword">new</span> Person(<span class="string">"zhuuu"</span>, <span class="number">3</span>);</span><br><span class="line">        System.out.println(p1==p2);</span><br><span class="line">        System.out.println(p1.equals(p2));</span><br><span class="line"></span><br><span class="line">        Person p3 = <span class="keyword">new</span> Person(<span class="string">"朱酱酱"</span>, <span class="number">24</span>);</span><br><span class="line">        System.out.println(p1.equals(p3));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>通过重写 equals 方法，我们自定义两个对象相等的标尺为Person<strong>对象的两个属性都相等，则对象相等，否则不相等。</strong></p>
<p><strong>如果不重写 equals 方法，那么始终是调用 Object 类的equals 方法，也就是用 == 比较两个对象在栈内存中的引用地址是否相等。</strong></p>
<p>这个时候又有了一个Person的子类Man,也重写了equals方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.zhuuu;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Man</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String sex;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Man</span><span class="params">(String name, <span class="keyword">int</span> age, String sex)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(name, age);</span><br><span class="line">        <span class="keyword">this</span>.sex = sex;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="keyword">super</span>.equals(obj))&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 对象为空或者不是Person实例</span></span><br><span class="line">        <span class="keyword">if</span> (obj == <span class="keyword">null</span> || !(obj <span class="keyword">instanceof</span> Man))&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Man man = (Man) obj;</span><br><span class="line">        <span class="keyword">return</span> sex.equals(man.sex);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Person p = <span class="keyword">new</span> Person(<span class="string">"Tom"</span>,<span class="number">22</span>);</span><br><span class="line">        Man m = <span class="keyword">new</span> Man(<span class="string">"Tom"</span>, <span class="number">22</span>, <span class="string">"男"</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(p.equals(m)); <span class="comment">// true</span></span><br><span class="line">        System.out.println(m.equals(p));  <span class="comment">// false</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>通过打印结果我们发现 person.equals(man)得到的结果是 true，</p>
<p>而man.equals(person)得到的结果却是false,这显然是不正确的。</p>
<p><strong>问题出现在 instanceof 关键字上</strong></p>
<p>Man 是 Person 的子类，person instanceof Man 结果当然是false。这违反了我们上面说的<strong>对称性。</strong></p>
<p><strong>实际上用 instanceof 关键字是做不到对称性的要求的。这里推荐做法是用 getClass()方法取代 instanceof 运算符。getClass() 关键字也是 Object 类中的一个方法，作用是返回一个对象的运行时类，下面我们会详细讲解。</strong></p>
<p>那么，Person类中的equals方法应该修改为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span> == obj)&#123;<span class="comment">//引用相等那么两个对象当然相等</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(obj == <span class="keyword">null</span> || (getClass() != obj.getClass()))&#123;<span class="comment">//对象为空或者不是Person类的实例</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        Person otherPerson = (Person)obj;</span><br><span class="line">        <span class="keyword">if</span>(otherPerson.getPname().equals(<span class="keyword">this</span>.getPname()) &amp;&amp; otherPerson.getPage()==<span class="keyword">this</span>.getPage())&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>打印结果 person.equals(man)得到的结果是 false，</p>
<p>man.equals(person)得到的结果也是false，满足对称性。</p>
<p>注意：使用 getClass 不是绝对的，要根据情况而定，毕竟定义对象是否相等的标准是由程序员自己定义的。而且使用 getClass 不符合多态的定义，比如 AbstractSet 抽象类，它有两个子类 TreeSet 和 HashSet,他们分别使用不同的算法实现查找集合的操作，但无论集合采用哪种方式实现，都需要拥有对两个集合进行比较的功能，如果使用 getClass 实现equals方法的重写，那么就不能在两个不同子类的对象进行相等的比较。而且集合类比较特殊，其子类是不需要自定义相等的概念的。</p>
<p><strong>所以什么时候使用 instanceof 运算符，什么时候使用 getClass() 有如下建议：</strong></p>
<p><strong>①、如果子类能够拥有自己的相等概念，则对称性需求将强制采用 getClass 进行检测。</strong></p>
<p><strong>②、如果有超类决定相等的概念，那么就可以使用 instanceof 进行检测，这样可以在不同的子类的对象之间进行相等的比较。</strong></p>
<p>下面给出一个完美的 equals 方法的建议：</p>
<ol>
<li>显示参数命名为otherObject，稍后会将它转换成另一个叫做other的变量。</li>
<li>判断比较的两个对象引用是否相等，如果引用相等那么表示是同一个对象，那么自然相等。</li>
<li>如果otherObject为null，直接返回false表示不相等。</li>
<li>比较this和otherObject是否是同一个类：如果equals的语义在每个子类中有所改变，就是用getClass进行检测；如果所有的子类都有统一的定义，那么使用instanceof进行检测。</li>
<li>将otherObject转换成对应的类 类型变量。</li>
<li>最后对对象的属性进行比较。使用==比较基本类型，使用equals比较对象。如果都相等返回true,否则返回false.注意如果在子类中定义equals，则要包含super.equals(other)</li>
</ol>
<p>下面给出Person类中完整的equals方法的书写：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object otherObject)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//1、判断比较的两个对象引用是否相等，如果引用相等那么表示是同一个对象，那么当然相等</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span> == otherObject)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//2、如果 otherObject 为 null，直接返回false，表示不相等</span></span><br><span class="line">        <span class="keyword">if</span>(otherObject == <span class="keyword">null</span> )&#123;<span class="comment">//对象为空或者不是Person类的实例</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//3、比较 this 和 otherObject 是否是同一个类（注意下面两个只能使用一种）</span></span><br><span class="line">        <span class="comment">//3.1：如果 equals 的语义在每个子类中所有改变，就使用 getClass 检测</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.getClass() != otherObject.getClass())&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//3.2：如果所有的子类都有统一的定义，那么使用 instanceof 检测</span></span><br><span class="line">        <span class="keyword">if</span>(!(otherObject <span class="keyword">instanceof</span> Person))&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//4、将 otherObject 转换成对应的类类型变量</span></span><br><span class="line">        Person other = (Person) otherObject;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//5、最后对对象的属性进行比较。使用 == 比较基本类型，使用 equals 比较对象。如果都相等则返回true，否则返回false</span></span><br><span class="line">        <span class="comment">//   使用 Objects 工具类的 equals 方法防止比较的两个对象有一个为 null而报错，因为 null.equals() 是会抛异常的</span></span><br><span class="line">        <span class="keyword">return</span> Objects.equals(<span class="keyword">this</span>.pname,other.pname) &amp;&amp; <span class="keyword">this</span>.page == other.page;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//6、注意如果是在子类中定义equals，则要包含 super.equals(other)</span></span><br><span class="line">        <span class="comment">//return super.equals(other) &amp;&amp; Objects.equals(this.pname,other.pname) &amp;&amp; this.page == other.page;</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p><strong>请注意，无论何时重写此方法，通常都必须重写hashCode方法，以维护hashCode方法的一般约定，该方法声明相等对象必须具有相同的哈希代码。hashCode 也是 Object 类中的方法，后面会详细讲解。</strong></p>
<h2 id="4-getClass-方法"><a href="#4-getClass-方法" class="headerlink" title="4. getClass() 方法"></a>4. getClass() 方法</h2><p>官方文档：<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--" target="_blank" rel="noopener">https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--</a></p>
<p>上面我们在介绍 equals 方法时，介绍如果 equals 的语义在每个子类中有所改变，那么使用 getClass 检测，为什么这样说呢？</p>
<p><strong>getClass()在Object类中如下，作用是返回对象的运行时类</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> Class&lt;?&gt; getClass();</span><br></pre></td></tr></table></figure>

<p>这里我们要知道用 native 修饰的方法我们不用考虑，由操作系统帮我们实现，该方法的作用是返回一个对象的运行时类,通过这个类对象我们可以获取该运行时类的相关属性和方法，也就是java中的反射，各种通用的框架都是利用反射来实现的，这里就不做详细阐述了。</p>
<p>这里详细的介绍 getClass 方法返回的是一个对象的运行时类对象，这该怎么理解呢？Java中还有一种这样的用法，通过 类名.class 获取这个类的类对象 ，这两种用法有什么区别呢？</p>
<ul>
<li>父类：Parent.class</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Parent</span> </span>&#123;&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>子类：Son.class</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Parent</span></span>&#123;&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>测试：</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.zhuuu;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">getClassTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Parent p = <span class="keyword">new</span> Son();</span><br><span class="line">        System.out.println(p.getClass());</span><br><span class="line">        System.out.println(Parent<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结果：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">class com.zhuuu.Son</span><br><span class="line">class com.zhuuu.Parent</span><br></pre></td></tr></table></figure>

<p><strong>结论：</strong></p>
<p><strong>class 是一个类的属性，能获取该类编译时的类对象，</strong></p>
<p><strong>而 getClass() 是一个类的方法，它是获取该类运行时的类对象。</strong></p>
<p><strong>PS;</strong></p>
<p>还有一个需要大家注意的是，虽然Object类中getClass() 方法声明是：</p>
<p>public final native Class&lt; ? &gt; getClass();</p>
<p>返回的是一个 Class&lt;?&gt;，但是如下是能通过编译的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Class&lt;? extends String&gt; c = <span class="string">""</span>.getClass();</span><br><span class="line">System.out.println(c);</span><br></pre></td></tr></table></figure>

<p><strong>也就是说明类型为T的变量getClass方法的返回值类型其实是Class&lt;? extends T&gt;而非getClass方法中声明的Class&lt; ? &gt;。</strong></p>
<p>这在官方文档中也有说明：</p>
<p><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--" target="_blank" rel="noopener">https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--</a></p>
<h2 id="5-hashCode-方法"><a href="#5-hashCode-方法" class="headerlink" title="5. hashCode() 方法"></a>5. hashCode() 方法</h2><p>hashCode 在 Object 类中定义如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">native</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>

<p>这也是一个用 native 声明的本地方法，作用是返回对象的散列码，是 int 类型的数值。</p>
<p>那么这个方法存在的意义是什么呢?</p>
<p>我们知道在Java 中有几种集合类:比如List,Set,还有Map等，List集合一般是存放的元素是有序可重复的，Set存放的是无序不可重复的，而Map存放的是键值对。</p>
<p>前面我们说过判断一个元素是否相等可以通过 equals 方法，每增加一个元素，那么我们就通过 equals 方法判断集合中的每一个元素是否重复，但是如果集合中有10000个元素了，但我们新加入一个元素时，那就需要进行10000次equals方法的调用，这显然效率很低。</p>
<p>于是，<strong>Java集合设计者就采用了哈希表来实现。</strong>哈希算法也称为散列算法，是将数据以特定的算法产生的结果映射到一个地址上，这个结果就是由hashCode方法产生。这样一来，当即和要添加新的元素时候，先调用这个元素的hashCode方法，就一下能定位到它应该防止的物理位置上。</p>
<p>①、如果这个位置上没有元素，它就可以直接存储在这个位置上，不用再进行任何比较了；</p>
<p>②、如果这个位置上已经有元素了，就调用它的equals方法与新元素进行比较，相同的话就不存了；</p>
<p>③、不相同的话，也就是发生了Hash key相同导致冲突的情况，那么就在这个Hash key的地方产生一个链表，将所有产生相同HashCode的对象放到这个单链表上去，串在一起（很少出现）。这样一来实际调用equals方法的次数就大大降低了，几乎只需要一两次。</p>
<p><img src="http://zhuuu-bucket.oss-cn-beijing.aliyuncs.com/img/20200416/202222643.png" alt="mark"></p>
<p>这里有 A,B,C,D四个对象，分别通过 hashCode 方法产生了三个值，注意 A 和 B 对象调用 hashCode 产生的值是相同的，即 A.hashCode() = B.hashCode() = 0x001,发生了哈希冲突，这时候由于最先是插入了 A，在插入的B的时候，我们发现 B 是要插入到 A 所在的位置，而 A 已经插入了，这时候就通过调用 equals 方法判断 A 和 B 是否相同，如果相同就不插入 B，如果不同则将 B 插入到 A 后面的位置。所以对于 equals 方法和 hashCode 方法有如下要求：</p>
<p><strong>一 ： HashCode的要求：</strong></p>
<p>①、在程序运行时期间，只要对象的（字段的）变化不会影响equals方法的决策结果，那么，在这个期间，无论调用多少次hashCode，都必须返回同一个散列码。</p>
<p>②、通过equals调用返回true 的2个对象的hashCode一定一样。</p>
<p>③、通过equasl返回false 的2个对象的散列码不需要不同，也就是他们的hashCode方法的返回值允许出现相同的情况。</p>
<p>因此有如下结论：</p>
<ul>
<li>两个对象相等，其HashCode一定相同</li>
<li>两个对象不相等，其HashCode有可能相同</li>
<li>hashCode相同的两个对象，不一定相等</li>
<li>hashCode不同的两个对象，一定不相等</li>
</ul>
<p><strong>可能会有人疑问，对于不能重复的集合，为什么不直接通过 hashCode 对于每个元素都产生唯一的值，如果重复就是相同的值，这样不就不需要调用 equals 方法来判断是否相同了吗 ？</strong></p>
<p>实际上对于元素不是很多的情况下，直接通过hashCode产生唯一的索引值，通过这个索引值能找到元素，而且还能判断是否相同。比如数据库中的存储的数据，ID是有序排列的，我们能通过ID直接找到某个元素，如果新插入的元素ID已经有了，那就表示是重复数据，这就是很完美办法。</p>
<p>但是现实是存储的元素很难有这样的ID关键字，也就和难实现这种hashCode唯一算法，再者就算能实现，但是产生hashCode码是非常大的，这会超过Java所能表示的范围，很占用内存空间，所以也是不予考虑的。</p>
<p><strong>二、hashCode 编写指导：</strong></p>
<p>①、不同对象的hash码应该尽量不同，避免hash冲突，也就是算法获得的元素要尽量均匀分布。</p>
<p>②、hash 值是一个 int 类型，在Java中占用 4 个字节，也就是 2的32 次方，要避免溢出。</p>
<p>在 JDK 的 Integer类，Float 类，String 类等都重写了 hashCode 方法，我们自定义对象也可以参考这些类来写。</p>
<p>下面是JDK String类的hashCode源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> h = hash;</span><br><span class="line">    <span class="keyword">if</span> (h == <span class="number">0</span> &amp;&amp; value.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">char</span> val[] = value;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; value.length; i++) &#123;</span><br><span class="line">            h = <span class="number">31</span> * h + val[i];</span><br><span class="line">        &#125;</span><br><span class="line">        hash = h;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> h;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>再次提醒的是，对于Map集合，可以选取Java中的基本类型，还有引用类型String作为key，因为他们都按照规范重写了equals方法和hashCode方法。如果你用自己定义的对象作为key,那么一定要覆盖equals方法和hashCode方法，不然会有意外的错误发生。</strong></p>
<h3 id="5-1-hashcode-方法和-equals方法的区别和联系"><a href="#5-1-hashcode-方法和-equals方法的区别和联系" class="headerlink" title="5.1 hashcode()方法和 equals方法的区别和联系"></a>5.1 hashcode()方法和 equals方法的区别和联系</h3><p><strong>参考博客 ：</strong> <a href="https://www.cnblogs.com/justdojava/p/11271438.html" target="_blank" rel="noopener">https://www.cnblogs.com/justdojava/p/11271438.html</a></p>
<p><strong>有面试官会问：你重写过 hashcode 和 equals 么，为什么重写equals时必须重写hashCode方法？</strong>equals和hashCode都是Object对象中的非final方法，它们设计的目的就是被用来覆盖(override)的，所以在程序设计中还是经常需要处理这两个方法。下面我们一起来看一下，它们到底有什么区别，总结一波！</p>
<p>以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode：</p>
<p>当你把对象加入 HashSet 时，HashSet 会先计算对象的 hashcode 值来判断对象加入的位置，同时也会与其他已经加入的对象的 hashcode 值作比较，如果没有相符的 hashcode，HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象，这时会调用 equals（）方法来检查 hashcode 相等的对象是否真的相同。如果两者相同，HashSet 就不会让其加入操作成功。如果不同的话，就会重新散列到其他位置。（摘自我的 Java 启蒙书《Head fist java》第二版）。这样我们就大大减少了 equals 的次数，相应就大大提高了执行速度。</p>
<p>1.hashcode相等，equals不一定相等<br>2.equals相等，hashcode一定相等</p>
<p><strong>为什么两个对象有相同的 hashcode 值，它们也不一定是相等的？</strong><br>因为 hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞，但这也与数据值域分布的特性有关（所谓碰撞也就是指的是不同的对象得到相同的 hashCode）。</p>
<p>我们刚刚也提到了 HashSet,如果 HashSet 在对比的时候，同样的 hashcode 有多个对象，它会使用 equals() 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。</p>
<h2 id="6-toString方法"><a href="#6-toString方法" class="headerlink" title="6. toString方法"></a>6. toString方法</h2><p>该方法在 JDK 的源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> getClass().getName() + <span class="string">"@"</span> + Integer.toHexString(hashCode());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>getClass().getName()是返回对象的全类名（包含包名）</p>
<p>Integer.toHexString(hashCode()) 是以16进制无符号整数形式返回此哈希码的字符串表示形式。</p>
<p>打印某个对象时，默认是调用 toString 方法，比如 System.out.println(person),等价于 System.out.println(person.toString())</p>
<h2 id="7-notify-notifyAll-wait"><a href="#7-notify-notifyAll-wait" class="headerlink" title="7. notify()/notifyAll()/wait()"></a>7. notify()/notifyAll()/wait()</h2><p>这是用于多线程之间的通信方法，在讲解多线程已经详细描述，这里就不做讲解了。</p>
<h2 id="8-finalize-方法"><a href="#8-finalize-方法" class="headerlink" title="8. finalize() 方法"></a>8. finalize() 方法</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable </span>&#123; &#125;</span><br></pre></td></tr></table></figure>

<p>该方法用于垃圾回收，一般由 JVM 自动调用，一般不需要程序员去手动调用该方法。在讲解 JVM 的时候会详细展开描述。</p>
<h2 id="9-registerNatives-方法"><a href="#9-registerNatives-方法" class="headerlink" title="9. registerNatives() 方法"></a>9. registerNatives() 方法</h2><p>该方法在 Object 类中定义如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">registerNatives</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>

<p>这是一个本地方法，在native关键字中介绍，我们知道一个类定义了本地方法后，想要调用操作系统的实现，必须还要装在本地库，但是我们在Object.class类中具有很多本地方法，但是却没有看到本地库的载入代码。而且这是用private关键字声明的，在类外面根本调用不了，我们接着我往下看关于这个方法类似源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> &#123;</span><br><span class="line">    registerNatives();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>看到上面的代码，这就明白了吧。静态代码块就是一个类在初始化过程中必定会执行的内容，所以在类加载的时候是会执行该方法的，通过该方法来注册本地方法。</p>

      
      <!-- reward -->
      
      <div id="reward-btn">
        打赏
      </div>
      
    </div>
      <!-- copyright -->
      
        <div class="declare">
          <ul class="post-copyright">
            <li>
              <i class="ri-copyright-line"></i>
              <strong>版权声明： </strong s>
              本博客所有文章除特别声明外，均采用 <a href="https://www.apache.org/licenses/LICENSE-2.0.html" rel="external nofollow"
                target="_blank">Apache License 2.0</a> 许可协议。转载请注明出处！
            </li>
          </ul>
        </div>
        
    <footer class="article-footer">
      
          
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://zhuuu.work/2020/04/01/jdk_SourceCode/JDK1.8-01-Object/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JDK%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/" rel="tag">JDK源码分析</a></li></ul>


    </footer>

  </div>

  
  
  <nav class="article-nav">
    
      <a href="/2020/04/01/Leetcode/Leetcode-1111-%E6%9C%89%E6%95%88%E6%8B%AC%E5%8F%B7%E7%9A%84%E5%B5%8C%E5%A5%97%E6%B7%B1%E5%BA%A6/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            Leetcode-1111-有效括号的长度
          
        </div>
      </a>
    
    
      <a href="/2020/04/01/personal_server/%E6%9C%8D%E5%8A%A1%E5%99%A8-%E5%AE%9D%E5%A1%94%E6%90%AD%E5%BB%BA%E7%8E%AF%E5%A2%83/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">云服务器-环境搭建</div>
      </a>
    
  </nav>


  

  
  
<!-- valine评论 -->
<div id="vcomments-box">
    <div id="vcomments">
    </div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src='https://cdn.jsdelivr.net/npm/valine@1.3.10/dist/Valine.min.js'></script>
<script>
    new Valine({
        el: '#vcomments',
        notify: false,
        verify: '',
        app_id: '',
        app_key: '',
        path: window.location.pathname,
        avatar: 'mp',
        placeholder: '给我的文章加点评论吧~',
        recordIP: true
    });
    const infoEle = document.querySelector('#vcomments .info');
    if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
        infoEle.childNodes.forEach(function (item) {
            item.parentNode.removeChild(item);
        });
    }
</script>
<style>
    #vcomments-box {
        padding: 5px 30px;
    }

    @media screen and (max-width: 800px) {
        #vcomments-box {
            padding: 5px 0px;
        }
    }

    #vcomments-box #vcomments {
        background-color: #fff;
    }

    .v .vlist .vcard .vh {
        padding-right: 20px;
    }

    .v .vlist .vcard {
        padding-left: 10px;
    }
</style>

  

  
  
<div class="gitalk" id="gitalk-container"></div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1.5.0/dist/gitalk.css">


<script src="https://cdn.jsdelivr.net/npm/gitalk@1.5.0/dist/gitalk.min.js"></script>


<script src="https://cdn.jsdelivr.net/npm/blueimp-md5@2.10.0/js/md5.min.js"></script>

<script type="text/javascript">
  var gitalk = new Gitalk({
    clientID: 'db188ed8c86dc4b0dbf3',
    clientSecret: 'a58f92160e5a9efd726b7d533000a0737f3e3f3e',
    repo: 'Blog-comments',
    owner: 'Zhuuuuuuuu',
    admin: ['Zhuuuuuuuu'],
    // id: location.pathname,      // Ensure uniqueness and length less than 50
    id: md5(location.pathname),
    distractionFreeMode: false,  // Facebook-like distraction free mode
    pagerDirection: 'last'
  })

  gitalk.render('gitalk-container')
</script>

  

</article>
</section>
      <footer class="footer">
  <div class="outer">
    <ul class="list-inline">
      <li>
        &copy;
        2019-2021
        Zhuuu
      </li>
      <li>
        
      </li>
    </ul>
    <ul class="list-inline">
      <li>
        
        
        <span>
  <i>PV:<span id="busuanzi_value_page_pv"></span></i>
  <i>UV:<span id="busuanzi_value_site_uv"></span></i>
</span>
        
      </li>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
    <div class="to_top">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>
      </div>
    </main>
      <aside class="sidebar">
        <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="朱酱酱的学习博客"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/JVM/">JVM</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/JDK%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/">JDK源码</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/">多线程</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/Mysql/">Mysql</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/Redis/">Redis</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E8%AE%BE%E8%AE%A1%E8%80%85%E6%A8%A1%E5%BC%8F/">设计模式</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/MyBatis/">MyBatis</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/SpringMVC/">SpringMVC</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/Spring/">Spring</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/SpringBoot/">SpringBoot</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/">Linux</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/Leetcode/">Leetcode</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E5%89%8D%E7%AB%AF/">前端</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/">网络编程</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/photoshop/">photoshop</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="http://smartzhuuu.lofter.com/" target="_blank" rel="noopener">摄影</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/2020/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
      </aside>
      <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
      
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/jquery.justifiedGallery.min.js"></script>


<script src="/js/lazyload.min.js"></script>


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<script src="/js/share.js"></script>



<script src="/fancybox/jquery.fancybox.min.js"></script>




<script>
  try {
    var typed = new Typed("#subtitle", {
    strings: ['昨夜西风凋碧树。独上高楼，望尽天涯路','衣带渐宽终不悔，为伊消得人憔悴。','众里寻他千百度。蓦然回首，那人却在，灯火阑珊处。'],
    startDelay: 0,
    typeSpeed: 200,
    loop: true,
    backSpeed: 100,
    showCursor: true
    });
  } catch (err) {
  }
  
</script>




<script src="/js/tocbot.min.js"></script>

<script>
  // Tocbot_v4.7.0  http://tscanlin.github.io/tocbot/
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer:'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto',
    onClick: (e) => {
      $('.toc-link').removeClass('is-active-link');
      $(`a[href=${e.target.hash}]`).addClass('is-active-link');
      $(e.target.hash).scrollIntoView();
      return false;
    }
  });
</script>


<script>
  var ayerConfig = {
    mathjax: true
  }
</script>


<script src="/js/ayer.js"></script>


<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">


<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>



<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
      tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
      }
  });

  MathJax.Hub.Queue(function() {
      var all = MathJax.Hub.getAllJax(), i;
      for(i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
      }
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.6/unpacked/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>


<script type="text/javascript" src="https://js.users.51.la/20544303.js"></script>
  </div>
</body>

</html>